package com.webex.ta.hydra.gui.table.celleditor;

import com.webex.ta.hydra.gui.util.RolloverButton;
import com.webex.ta.hydra.util.HydraUtils;
import org.apache.commons.lang.StringUtils;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;

/**
 * Created by Cisco WebEx.
 * User: vegaz
 * Date: 2010-10-26
 * Time: 16:41:48
 */
public class HttpParamEditor extends DialogCellEditor {
    private static HttpParamEditComponent editor = new HttpParamEditComponent();

    @Override
    protected AbstractEditorDialogComponent getEditorComponent() {
        return editor;
    }

    private static class HttpParamEditComponent extends AbstractEditorDialogComponent {
        private JTable table;
        private HttpParamModel model;
        private JButton add, remove, up, down;

        public HttpParamEditComponent() {
            setLayout(new BorderLayout());
            this.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
            add = createSmallActionButton("include.png");
            remove = createSmallActionButton("exclude.png");
            up = createSmallActionButton("moveup.gif");
            down = createSmallActionButton("movedown.gif");
            add.addActionListener(new AddAction());
            remove.addActionListener(new RemoveAction());
            up.addActionListener(new UpAction());
            down.addActionListener(new DownAction());

            Box box = Box.createHorizontalBox();
            box.add(add);
            box.add(remove);
            box.add(up);
            box.add(down);
            add(box, BorderLayout.NORTH);

            model = new HttpParamModel();
            table = new JTable(model);
            table.setSurrendersFocusOnKeystroke(true);
            table.getTableHeader().setReorderingAllowed(false);
            JScrollPane scroll = new JScrollPane(table);
            scroll.setPreferredSize(new Dimension(400, 300));

            this.add(scroll, BorderLayout.CENTER);
        }

        private JButton createSmallActionButton(String icon) {
            JButton button = new RolloverButton(HydraUtils.getImage(icon));
            button.setBorderPainted(false);
            button.setPreferredSize(new Dimension(18, 18));
            button.setMaximumSize(new Dimension(18, 18));
            return button;
        }

        public String getValue() {
            if (table.isEditing()) {
                table.getCellEditor().stopCellEditing();
            }
            StringBuffer sb = new StringBuffer("");
            ArrayList<HttpParam> params = model.getParams();
            for (int i = 0; i < params.size(); i++) {
                HttpParam param = params.get(i);
                sb.append(param.name);
                sb.append("=");
                try {
                    if (param.value != null)
                        sb.append(URLEncoder.encode(param.value, "UTF-8"));
                    else
                        sb.append("");
                } catch (UnsupportedEncodingException ignore) {
                }
                if (i < params.size() - 1)
                    sb.append("&");
            }
            return sb.toString();
        }

        public void reset() {
            if (table.isEditing()) {
                table.getCellEditor().cancelCellEditing();
            }
            model.clear();
        }

        public void setValue(String value) {
            if (value == null) return;
            String[] entries = StringUtils.split(value, "&");
            for (String entry : entries) {
                HttpParam param = new HttpParam();
                int start = entry.indexOf("=");
                if (start < 0) {
                    param.name = entry;
                } else {
                    param.name = entry.substring(0, start);
                    try {
                        param.value = URLDecoder.decode(entry.substring(start + 1), "UTF-8");
                    } catch (UnsupportedEncodingException ignore) {
                    }
                }
                model.add(param);
            }
        }

        private class AddAction implements ActionListener {
            public void actionPerformed(ActionEvent e) {
                model.add(new HttpParam());
            }
        }

        private class RemoveAction implements ActionListener {
            public void actionPerformed(ActionEvent e) {
                if (table.getSelectedRow() >= 0) {
                    int[] selection = table.getSelectedRows();
                    for (int i = selection.length - 1; i >= 0; i--) {
                        model.remove(selection[i]);
                    }
                }
            }
        }

        private class UpAction implements ActionListener {
            public void actionPerformed(ActionEvent e) {
                int row = table.getSelectedRow();
                if (row > 0) {
                    if (table.isEditing())
                        table.getCellEditor().stopCellEditing();
                    HttpParam current = model.remove(row);
                    model.insert(current, row - 1);
                }
            }
        }

        private class DownAction implements ActionListener {
            public void actionPerformed(ActionEvent e) {
                int row = table.getSelectedRow();
                if (row >= 0 && row < table.getRowCount() - 1) {
                    if (table.isEditing())
                        table.getCellEditor().stopCellEditing();
                    HttpParam current = model.remove(row);
                    model.insert(current, row + 1);
                }
            }
        }
    }

    private static class HttpParam {
        public String name = "";
        public String value = "";
    }

    private static class HttpParamModel extends AbstractTableModel {
        ArrayList<HttpParam> params = new ArrayList<HttpParam>();

        public void clear() {
            params.clear();
            this.fireTableDataChanged();
        }

        public void add(HttpParam param) {
            params.add(param);
            this.fireTableRowsInserted(params.size(), params.size());
        }

        public void insert(HttpParam param, int index) {
            params.add(index, param);
            this.fireTableRowsInserted(index, index);
        }

        public HttpParam remove(int index) {
            HttpParam removed = params.remove(index);
            this.fireTableRowsDeleted(index, index);
            return removed;
        }

        public ArrayList<HttpParam> getParams() {
            return params;
        }


        public int getColumnCount() {
            return 2;
        }

        @Override
        public String getColumnName(int column) {
            switch (column) {
                case 0:
                    return "Name:";
                case 1:
                    return "Value";
            }
            return "";
        }

        public int getRowCount() {
            return params.size();
        }

        public Object getValueAt(int row, int column) {
            HttpParam param = params.get(row);
            if (column == 0)
                return param.name;
            else if (column == 1)
                return param.value;
            return null;
        }

        @Override
        public boolean isCellEditable(int row, int column) {
            return true;
        }

        @Override
        public void setValueAt(Object value, int row, int column) {
            HttpParam param = params.get(row);
            switch (column) {
                case 0:
                    param.name = value.toString();
                    break;
                case 1:
                    param.value = value.toString();
                    break;
            }
        }
    }
}
